#pragma once
#include <lvgl.h>
#include <array>



namespace gui
{
    constexpr uint16_t DISP_HOR_RES = 480;
    constexpr uint16_t DISP_VER_RES = 320;
    constexpr uint16_t DISP_BUF_SIZE = 20; //20
    constexpr uint8_t BYTE_PER_PIXEL = (LV_COLOR_FORMAT_GET_SIZE(LV_COLOR_FORMAT_RGB565));

    /**
     * @brief Render类
     * @tparam UIPolicy UI策略类，这里使用的是LVGL，需要实现屏幕初始化函数screenInit()和事件初始化函数eventInit()
     * @note 渲染类，用于初始化GUI和运行GUI。组件需要定义在gui::widgets::main命名空间
     */
    class control
    {
        using LCD_Init_Func = void (*)();
        using LCD_Flush_Func = void (*)(uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2, uint8_t *color_p);
        using Touch_Init_Func = int32_t (*)(int32_t *last_x, int32_t *last_y);
    public:
        template<typename UIPolicy,LCD_Init_Func lcd_init, LCD_Flush_Func disp_flush,Touch_Init_Func  touchpad_read_xy =  nullptr>
        static auto init() -> void
        {
            /********初始化LVGL*******/
            lv_init();

            /********初始化LCD*******/
            if constexpr (lcd_init != nullptr){lcd_init();}

            /******初始化显示设备******/
            if constexpr (disp_flush != nullptr) { disp_drv_init<disp_flush>(); }

            /*****初始化触摸屏******/
            if constexpr (touchpad_read_xy != nullptr) { touchpad_init<touchpad_read_xy>(); }

            /*****初始化UI资源*****/
            // widgets::main::scr.init().size(DISP_HOR_RES, DISP_VER_RES);// 默认父对象为nullpter
            // compose::Component::parent(widgets::main::scr);// 默认主屏幕为父对象
            UIPolicy::screenInit();// 初始化屏幕
            UIPolicy::eventInit();// 初始化事件

        }

        // GUI处理函数
        [[gnu::always_inline]] static inline auto handler() -> void { lv_task_handler(); }

        [[gnu::always_inline]] static inline auto tick_inc(){lv_tick_inc(1);}

        // 刷新回调,可供DMA回调函数使用
        [[gnu::always_inline]] static inline auto display_flush_ready() -> void { lv_display_flush_ready(disp); }

        // 获取设备
        [[gnu::always_inline]] static inline auto get_display() -> lv_display_t * { return disp; }
        [[gnu::always_inline]] static inline auto get_indev() -> lv_indev_t * { return indev_touchpad; }


    private:

        /**
         * @brief 初始化显示驱动
         * @tparam flush 涂色函数，有LCD驱动提供
         * @note 为了让lambda表达式可以不用捕获外部函数，只能使用函数模板。如果使用函数指针来传递就必须要显示捕获
         */
        template<void (*flush)(uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2, uint8_t *color_p)>
        static inline auto disp_drv_init() -> void
        {
            disp = lv_display_create(DISP_HOR_RES, DISP_VER_RES);

            // 刷新回调
            lv_display_set_flush_cb(disp, [](lv_display_t *disp_drv, const lv_area_t *area, uint8_t *px_map)
            {
                flush(area->x1, area->y1, area->x2, area->y2, px_map);

                // 只有定义了DMA中断回调才不需要这个函数，那么这就要求DMA中断启用时需要设置相关宏定义
#if !defined(ARM_MATH_CM4) || !defined(DMA_SPI_ENABLE)
                display_flush_ready();
#endif
            });


            // 缓冲区  双缓冲明显优于单缓冲
            LV_ATTRIBUTE_MEM_ALIGN
            static std::array<uint8_t,DISP_HOR_RES * DISP_BUF_SIZE * BYTE_PER_PIXEL> buf_2_1;
            LV_ATTRIBUTE_MEM_ALIGN
            static std::array<uint8_t,DISP_HOR_RES * DISP_BUF_SIZE * BYTE_PER_PIXEL> buf_2_2;
            lv_display_set_buffers(disp, buf_2_1.data(), buf_2_2.data(), buf_2_1.size(), LV_DISPLAY_RENDER_MODE_PARTIAL);
        }

        /**
         * @brief 初始化触摸屏驱动
         * @tparam touchpad_read_xy
         */
        template<int32_t (*touchpad_read_xy)(int32_t *last_x, int32_t *last_y)>
        static inline auto touchpad_init() -> void
        {
            indev_touchpad = lv_indev_create();
            lv_indev_set_type(indev_touchpad, LV_INDEV_TYPE_POINTER);
            lv_indev_set_read_cb(indev_touchpad, [](lv_indev_t *indev_drv, lv_indev_data_t *data)
            {
                if (touchpad_read_xy(&(data->point.x), &(data->point.y)))
                {
                    data->state = LV_INDEV_STATE_PRESSED;
                }
                else
                {
                    data->state = LV_INDEV_STATE_RELEASED;
                }
            });
        }

        // 显示设备
        static inline lv_display_t *disp;
        static inline lv_indev_t *indev_touchpad;
    };
}






